
#ifndef __LIBERTY_ENGINE_COMPONENT_H__
#define __LIBERTY_ENGINE_COMPONENT_H__

#include <Liberty3D/Liberty3D.h>

#include <Liberty3D/Engine/ISerializable.h>

#include <Liberty3D/Engine/Object.h>
#include <Liberty3D/Engine/IComponentFactory.h>

namespace Liberty { namespace Engine {
    enum ComponentCalls {
        Update           = 0x0001,
        LateUpdate       = 0x0002,
        FixedUpdate      = 0x0004,

        PreCull          = 0x0010,
        WillRenderObject = 0x0020,
        PreRender        = 0x0040,
        RenderObject     = 0x0080,
        PostRender       = 0x0100,
        RenderImage      = 0x0200,
        GUI              = 0x0400,
        DrawGizmos       = 0x0800,
    };

    typedef unsigned short ComponentCallsFlags;

    class Component : public Object, public ISerializable {
        friend class Context;

    protected:
        ComponentCallsFlags       _calls;
        std::weak_ptr<GameObject> _parent;

    public:
        Component();
        virtual ~Component();

    public:
        std::shared_ptr<Context>    context() const;
        std::shared_ptr<GameObject> gameObject() const { return _parent.lock(); }

    public:
        virtual std::string name() const;
        virtual void setName(const std::string& name);

    public:
        virtual void onStart();

        virtual void onUpdate();
        virtual void onLateUpdate();
        virtual void onFixedUpdate();

        virtual void onPreCull();
        virtual void onWillRenderObject();
        virtual void onRenderObject();
        virtual void onPostRender();
        virtual void onRenderImage();
        virtual void onGui();
        virtual void onDrawGizmos();

    public:
        inline ComponentCallsFlags calls() const { return _calls; }

    public:
        virtual int order() const;

        /**
         * Static components are components that doesn't perform any action.
         * Their only function is to store information for other components
         * that is never update by the normal cycling.
         *
         * They are kept out of the live 'Components' by the Context object.
         */
        virtual bool staticComponent() const;

    public:
        virtual std::shared_ptr<IObjectMethod> findMethod(const std::string& methodName);

    public: // ISerializable
        virtual void serializeObject(ISerializer*);
    };
}}

#endif
